home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / lisp / stk-3.002 / stk-3 / STk-3.1 / Tk / generic / tkFrame.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-31  |  24.3 KB  |  794 lines

  1. /* 
  2.  * tkFrame.c --
  3.  *
  4.  *    This module implements "frame"  and "toplevel" widgets for
  5.  *    the Tk toolkit.  Frames are windows with a background color
  6.  *    and possibly a 3-D effect, but not much else in the way of
  7.  *    attributes.
  8.  *
  9.  * Copyright (c) 1990-1994 The Regents of the University of California.
  10.  * Copyright (c) 1994-1995 Sun Microsystems, Inc.
  11.  *
  12.  * See the file "license.terms" for information on usage and redistribution
  13.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14.  *
  15.  * SCCS: @(#) tkFrame.c 1.68 96/02/15 18:53:30
  16.  */
  17.  
  18. #include "default.h"
  19. #include "tkPort.h"
  20. #include "tkInt.h"
  21.  
  22. /*
  23.  * A data structure of the following type is kept for each
  24.  * frame that currently exists for this process:
  25.  */
  26.  
  27. typedef struct {
  28.     Tk_Window tkwin;        /* Window that embodies the frame.  NULL
  29.                  * means that the window has been destroyed
  30.                  * but the data structures haven't yet been
  31.                  * cleaned up. */
  32.     Display *display;        /* Display containing widget.  Used, among
  33.                  * other things, so that resources can be
  34.                  * freed even after tkwin has gone away. */
  35.     Tcl_Interp *interp;        /* Interpreter associated with widget.  Used
  36.                  * to delete widget command. */
  37.     Tcl_Command widgetCmd;    /* Token for frame's widget command. */
  38.     char *className;        /* Class name for widget (from configuration
  39.                  * option).  Malloc-ed. */
  40.     int mask;            /* Either FRAME or TOPLEVEL;  used to select
  41.                  * which configuration options are valid for
  42.                  * widget. */
  43.     char *screenName;        /* Screen on which widget is created.  Non-null
  44.                  * only for top-levels.  Malloc-ed, may be
  45.                  * NULL. */
  46.     char *visualName;        /* Textual description of visual for window,
  47.                  * from -visual option.  Malloc-ed, may be
  48.                  * NULL. */
  49.     char *colormapName;        /* Textual description of colormap for window,
  50.                  * from -colormap option.  Malloc-ed, may be
  51.                  * NULL. */
  52.     Colormap colormap;        /* If not None, identifies a colormap
  53.                  * allocated for this window, which must be
  54.                  * freed when the window is deleted. */
  55.     Tk_3DBorder border;        /* Structure used to draw 3-D border and
  56.                  * background.  NULL means no background
  57.                  * or border. */
  58.     int borderWidth;        /* Width of 3-D border (if any). */
  59.     int relief;            /* 3-d effect: TK_RELIEF_RAISED etc. */
  60.     int highlightWidth;        /* Width in pixels of highlight to draw
  61.                  * around widget when it has the focus.
  62.                  * 0 means don't draw a highlight. */
  63.     XColor *highlightBgColorPtr;
  64.                 /* Color for drawing traversal highlight
  65.                  * area when highlight is off. */
  66.     XColor *highlightColorPtr;    /* Color for drawing traversal highlight. */
  67.     int width;            /* Width to request for window.  <= 0 means
  68.                  * don't request any size. */
  69.     int height;            /* Height to request for window.  <= 0 means
  70.                  * don't request any size. */
  71.     Tk_Cursor cursor;        /* Current cursor for window, or None. */
  72.     char *takeFocus;        /* Value of -takefocus option;  not used in
  73.                  * the C code, but used by keyboard traversal
  74.                  * scripts.  Malloc'ed, but may be NULL. */
  75.     int flags;            /* Various flags;  see below for
  76.                  * definitions. */
  77. } Frame;
  78.  
  79. /*
  80.  * Flag bits for frames:
  81.  *
  82.  * REDRAW_PENDING:        Non-zero means a DoWhenIdle handler
  83.  *                has already been queued to redraw
  84.  *                this window.
  85.  * GOT_FOCUS:            Non-zero means this widget currently
  86.  *                has the input focus.
  87.  */
  88.  
  89. #define REDRAW_PENDING        1
  90. #define GOT_FOCUS        4
  91.  
  92. /*
  93.  * The following flag bits are used so that there can be separate
  94.  * defaults for some configuration options for frames and toplevels.
  95.  */
  96.  
  97. #define FRAME        TK_CONFIG_USER_BIT
  98. #define TOPLEVEL    (TK_CONFIG_USER_BIT << 1)
  99. #define BOTH        (FRAME | TOPLEVEL)
  100.  
  101. static Tk_ConfigSpec configSpecs[] = {
  102.     {TK_CONFIG_BORDER, "-background", "background", "Background",
  103.     DEF_FRAME_BG_COLOR, Tk_Offset(Frame, border),
  104.     BOTH|TK_CONFIG_COLOR_ONLY|TK_CONFIG_NULL_OK},
  105.     {TK_CONFIG_BORDER, "-background", "background", "Background",
  106.     DEF_FRAME_BG_MONO, Tk_Offset(Frame, border),
  107.     BOTH|TK_CONFIG_MONO_ONLY|TK_CONFIG_NULL_OK},
  108.     {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
  109.     (char *) NULL, 0, BOTH},
  110.     {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
  111.     (char *) NULL, 0, BOTH},
  112.     {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
  113.     DEF_FRAME_BORDER_WIDTH, Tk_Offset(Frame, borderWidth), BOTH},
  114.     {TK_CONFIG_STRING, "-class", "class", "Class",
  115.     DEF_FRAME_CLASS, Tk_Offset(Frame, className), FRAME},
  116.     {TK_CONFIG_STRING, "-class", "class", "Class",
  117.     DEF_TOPLEVEL_CLASS, Tk_Offset(Frame, className), TOPLEVEL},
  118.     {TK_CONFIG_STRING, "-colormap", "colormap", "Colormap",
  119.     DEF_FRAME_COLORMAP, Tk_Offset(Frame, colormapName),
  120.     BOTH|TK_CONFIG_NULL_OK},
  121.     {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
  122.     DEF_FRAME_CURSOR, Tk_Offset(Frame, cursor), BOTH|TK_CONFIG_NULL_OK},
  123.     {TK_CONFIG_PIXELS, "-height", "height", "Height",
  124.     DEF_FRAME_HEIGHT, Tk_Offset(Frame, height), BOTH},
  125.     {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
  126.     "HighlightBackground", DEF_FRAME_HIGHLIGHT_BG,
  127.     Tk_Offset(Frame, highlightBgColorPtr), BOTH},
  128.     {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
  129.     DEF_FRAME_HIGHLIGHT, Tk_Offset(Frame, highlightColorPtr), BOTH},
  130.     {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
  131.     "HighlightThickness",
  132.     DEF_FRAME_HIGHLIGHT_WIDTH, Tk_Offset(Frame, highlightWidth), BOTH},
  133.     {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
  134.     DEF_FRAME_RELIEF, Tk_Offset(Frame, relief), BOTH},
  135.     {TK_CONFIG_STRING, "-screen", "screen", "Screen",
  136.     DEF_TOPLEVEL_SCREEN, Tk_Offset(Frame, screenName),
  137.     TOPLEVEL|TK_CONFIG_NULL_OK},
  138. #ifdef STk_CODE
  139.     {TK_CONFIG_CLOSURE, "-takefocus", "takeFocus", "TakeFocus",
  140. #else
  141.     {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
  142. #endif
  143.     DEF_FRAME_TAKE_FOCUS, Tk_Offset(Frame, takeFocus),
  144.     BOTH|TK_CONFIG_NULL_OK},
  145.     {TK_CONFIG_STRING, "-visual", "visual", "Visual",
  146.     DEF_FRAME_VISUAL, Tk_Offset(Frame, visualName),
  147.     BOTH|TK_CONFIG_NULL_OK},
  148.     {TK_CONFIG_PIXELS, "-width", "width", "Width",
  149.     DEF_FRAME_WIDTH, Tk_Offset(Frame, width), BOTH},
  150.     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
  151.     (char *) NULL, 0, 0}
  152. };
  153.  
  154. /*
  155.  * Forward declarations for procedures defined later in this file:
  156.  */
  157.  
  158. static int        ConfigureFrame _ANSI_ARGS_((Tcl_Interp *interp,
  159.                 Frame *framePtr, int argc, char **argv,
  160.                 int flags));
  161. static void        DestroyFrame _ANSI_ARGS_((char *memPtr));
  162. static void        DisplayFrame _ANSI_ARGS_((ClientData clientData));
  163. static void        FrameCmdDeletedProc _ANSI_ARGS_((
  164.                 ClientData clientData));
  165. static void        FrameEventProc _ANSI_ARGS_((ClientData clientData,
  166.                 XEvent *eventPtr));
  167. static int        FrameWidgetCmd _ANSI_ARGS_((ClientData clientData,
  168.                 Tcl_Interp *interp, int argc, char **argv));
  169. static void        MapFrame _ANSI_ARGS_((ClientData clientData));
  170.  
  171. /*
  172.  *--------------------------------------------------------------
  173.  *
  174.  * Tk_FrameCmd, Tk_ToplevelCmd --
  175.  *
  176.  *    These procedures are invoked to process the "frame" and
  177.  *    "toplevel" Tcl commands.  See the user documentation for
  178.  *    details on what they do.
  179.  *
  180.  * Results:
  181.  *    A standard Tcl result.
  182.  *
  183.  * Side effects:
  184.  *    See the user documentation.  These procedures are just wrappers;
  185.  *    they call ButtonCreate to do all of the real work.
  186.  *
  187.  *--------------------------------------------------------------
  188.  */
  189.  
  190. int
  191. Tk_FrameCmd(clientData, interp, argc, argv)
  192.     ClientData clientData;    /* Main window associated with
  193.                  * interpreter. */
  194.     Tcl_Interp *interp;        /* Current interpreter. */
  195.     int argc;            /* Number of arguments. */
  196.     char **argv;        /* Argument strings. */
  197. {
  198.     return TkCreateFrame(clientData, interp, argc, argv, 0, (char *) NULL);
  199. }
  200.  
  201. int
  202. Tk_ToplevelCmd(clientData, interp, argc, argv)
  203.     ClientData clientData;    /* Main window associated with
  204.                  * interpreter. */
  205.     Tcl_Interp *interp;        /* Current interpreter. */
  206.     int argc;            /* Number of arguments. */
  207.     char **argv;        /* Argument strings. */
  208. {
  209.     return TkCreateFrame(clientData, interp, argc, argv, 1, (char *) NULL);
  210. }
  211.  
  212. /*
  213.  *--------------------------------------------------------------
  214.  *
  215.  * TkFrameCreate --
  216.  *
  217.  *    This procedure is invoked to process the "frame" and "toplevel"
  218.  *    Tcl commands;  it is also invoked directly by Tk_Init to create
  219.  *    a new main window.  See the user documentation for the "frame"
  220.  *    and "toplevel" commands for details on what it does.
  221.  *
  222.  * Results:
  223.  *    A standard Tcl result.
  224.  *
  225.  * Side effects:
  226.  *    See the user documentation.
  227.  *
  228.  *--------------------------------------------------------------
  229.  */
  230.  
  231. int
  232. TkCreateFrame(clientData, interp, argc, argv, toplevel, appName)
  233.     ClientData clientData;    /* Main window associated with interpreter.
  234.                  * If we're called by Tk_Init to create a
  235.                  * new application, then this is NULL. */
  236.     Tcl_Interp *interp;        /* Current interpreter. */
  237.     int argc;            /* Number of arguments. */
  238.     char **argv;        /* Argument strings. */
  239.     int toplevel;        /* Non-zero means create a toplevel window,
  240.                  * zero means create a frame. */
  241.     char *appName;        /* Should only be non-NULL if clientData is
  242.                  * NULL:  gives the base name to use for the
  243.                  * new application. */
  244. {
  245.     Tk_Window tkwin = (Tk_Window) clientData;
  246.     Frame *framePtr;
  247.     Tk_Window new = NULL;
  248.     char *className, *screenName, *visualName, *colormapName, *arg;
  249.     int i, c, length, depth;
  250.     Colormap colormap;
  251.     Visual *visual;
  252.  
  253.     if (argc < 2) {
  254.     Tcl_AppendResult(interp, "wrong # args: should be \"",
  255.         argv[0], " pathName ?options?\"", (char *) NULL);
  256.     return TCL_ERROR;
  257.     }
  258.  
  259.     /*
  260.      * Pre-process the argument list.  Scan through it to find any
  261.      * "-class", "-screen", "-visual", and "-colormap" options.  These
  262.      * arguments need to be processed specially, before the window
  263.      * is configured using the usual Tk mechanisms.
  264.      */
  265.  
  266.     className = colormapName = screenName = visualName = NULL;
  267.     colormap = None;
  268.     for (i = 2; i < argc; i += 2) {
  269.     arg = argv[i];
  270.     length = strlen(arg);
  271.     if (length < 2) {
  272.         continue;
  273.     }
  274.     c = arg[1];
  275.     if ((c == 'c') && (strncmp(arg, "-class", strlen(arg)) == 0)
  276.         && (length >= 3)) {
  277.         className = argv[i+1];
  278.     } else if ((c == 'c')
  279.         && (strncmp(arg, "-colormap", strlen(arg)) == 0)) {
  280.         colormapName = argv[i+1];
  281.     } else if ((c == 's') && toplevel
  282.         && (strncmp(arg, "-screen", strlen(arg)) == 0)) {
  283.         screenName = argv[i+1];
  284.     } else if ((c == 'v')
  285.         && (strncmp(arg, "-visual", strlen(arg)) == 0)) {
  286.         visualName = argv[i+1];
  287.     }
  288.     }
  289.  
  290.     /*
  291.      * Create the window, and deal with the special options -classname,
  292.      * -colormap, -screenname, and -visual.  The order here is tricky,
  293.      * because we want to allow values for these options to come from
  294.      * the database, yet we can't do that until the window is created.
  295.      */
  296.  
  297.     if (screenName == NULL) {
  298.     screenName = (toplevel) ? "" : NULL;
  299.     }
  300.     if (tkwin != NULL) {
  301.     new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], screenName);
  302.     } else {
  303.     /*
  304.      * We were called from Tk_Init;  create a new application.
  305.      */
  306.  
  307.     if (appName == NULL) {
  308.         panic("TkCreateFrame didn't get application name");
  309.     }
  310.     new = TkCreateMainWindow(interp, screenName, appName);
  311.     }
  312.     if (new == NULL) {
  313.     goto error;
  314.     }
  315.     if (className == NULL) {
  316.     className = Tk_GetOption(new, "class", "Class");
  317.     if (className == NULL) {
  318.         className = (toplevel) ? "Toplevel" : "Frame";
  319.     }
  320.     }
  321.     Tk_SetClass(new, className);
  322.     if (visualName == NULL) {
  323.     visualName = Tk_GetOption(new, "visual", "Visual");
  324.     }
  325.     if (colormapName == NULL) {
  326.     colormapName = Tk_GetOption(new, "colormap", "Colormap");
  327.     }
  328.     if (visualName != NULL) {
  329.     visual = Tk_GetVisual(interp, new, visualName, &depth,
  330.         (colormapName == NULL) ? &colormap : (Colormap *) NULL);
  331.     if (visual == NULL) {
  332.         goto error;
  333.     }
  334.     Tk_SetWindowVisual(new, visual, depth, colormap);
  335.     }
  336.     if (colormapName != NULL) {
  337.     colormap = Tk_GetColormap(interp, new, colormapName);
  338.     if (colormap == None) {
  339.         goto error;
  340.     }
  341.     Tk_SetWindowColormap(new, colormap);
  342.     }
  343.  
  344.     /*
  345.      * For top-level windows, provide an initial geometry request of
  346.      * 200x200,  just so the window looks nicer on the screen if it
  347.      * doesn't request a size for itself.
  348.      */
  349.  
  350.     if (toplevel) {
  351.     Tk_GeometryRequest(new, 200, 200);
  352.     }
  353.  
  354.     /*
  355.      * Create the widget record, process configuration options, and
  356.      * create event handlers.  Then fill in a few additional fields
  357.      * in the widget record from the special options.
  358.      */
  359.  
  360.     framePtr = (Frame *) ckalloc(sizeof(Frame));
  361.     framePtr->tkwin = new;
  362.     framePtr->display = Tk_Display(new);
  363.     framePtr->interp = interp;
  364.     framePtr->widgetCmd = Tcl_CreateCommand(interp,
  365.         Tk_PathName(new), FrameWidgetCmd,
  366.         (ClientData) framePtr, FrameCmdDeletedProc);
  367.     framePtr->className = NULL;
  368.     framePtr->mask = (toplevel) ? TOPLEVEL : FRAME;
  369.     framePtr->screenName = NULL;
  370.     framePtr->visualName = NULL;
  371.     framePtr->colormapName = NULL;
  372.     framePtr->colormap = colormap;
  373.     framePtr->border = NULL;
  374.     framePtr->borderWidth = 0;
  375.     framePtr->relief = TK_RELIEF_FLAT;
  376.     framePtr->highlightWidth = 0;
  377.     framePtr->highlightBgColorPtr = NULL;
  378.     framePtr->highlightColorPtr = NULL;
  379.     framePtr->width = 0;
  380.     framePtr->height = 0;
  381.     framePtr->cursor = None;
  382.     framePtr->takeFocus = NULL;
  383.     framePtr->flags = 0;
  384.     Tk_CreateEventHandler(new, ExposureMask|StructureNotifyMask|FocusChangeMask,
  385.         FrameEventProc, (ClientData) framePtr);
  386.     if (ConfigureFrame(interp, framePtr, argc-2, argv+2, 0) != TCL_OK) {
  387.     goto error;
  388.     }
  389.     if (toplevel) {
  390.     Tcl_DoWhenIdle(MapFrame, (ClientData) framePtr);
  391.     }
  392. #ifdef STk_CODE
  393.      STk_sharp_dot_result(interp,Tk_PathName(new));
  394. #else
  395.     interp->result = Tk_PathName(new);
  396. #endif
  397.     return TCL_OK;
  398.  
  399.     error:
  400.     if (new != NULL) {
  401.     Tk_DestroyWindow(new);
  402.     }
  403.     return TCL_ERROR;
  404. }
  405.  
  406. /*
  407.  *--------------------------------------------------------------
  408.  *
  409.  * FrameWidgetCmd --
  410.  *
  411.  *    This procedure is invoked to process the Tcl command
  412.  *    that corresponds to a frame widget.  See the user
  413.  *    documentation for details on what it does.
  414.  *
  415.  * Results:
  416.  *    A standard Tcl result.
  417.  *
  418.  * Side effects:
  419.  *    See the user documentation.
  420.  *
  421.  *--------------------------------------------------------------
  422.  */
  423.  
  424. static int
  425. FrameWidgetCmd(clientData, interp, argc, argv)
  426.     ClientData clientData;    /* Information about frame widget. */
  427.     Tcl_Interp *interp;        /* Current interpreter. */
  428.     int argc;            /* Number of arguments. */
  429.     char **argv;        /* Argument strings. */
  430. {
  431.     register Frame *framePtr = (Frame *) clientData;
  432.     int result = TCL_OK;
  433.     size_t length;
  434.     int c, i;
  435.  
  436.     if (argc < 2) {
  437.     Tcl_AppendResult(interp, "wrong # args: should be \"",
  438.         argv[0], " option ?arg arg ...?\"", (char *) NULL);
  439.     return TCL_ERROR;
  440.     }
  441.     Tcl_Preserve((ClientData) framePtr);
  442.     c = argv[1][0];
  443.     length = strlen(argv[1]);
  444.     if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
  445.         && (length >= 2)) {
  446.     if (argc != 3) {
  447.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  448.             argv[0], " cget option\"",
  449.             (char *) NULL);
  450.         result = TCL_ERROR;
  451.         goto done;
  452.     }
  453.     result = Tk_ConfigureValue(interp, framePtr->tkwin, configSpecs,
  454.         (char *) framePtr, argv[2], framePtr->mask);
  455.     } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
  456.         && (length >= 2)) {
  457.     if (argc == 2) {
  458.         result = Tk_ConfigureInfo(interp, framePtr->tkwin, configSpecs,
  459.             (char *) framePtr, (char *) NULL, framePtr->mask);
  460.     } else if (argc == 3) {
  461.         result = Tk_ConfigureInfo(interp, framePtr->tkwin, configSpecs,
  462.             (char *) framePtr, argv[2], framePtr->mask);
  463.     } else {
  464.         /*
  465.          * Don't allow the options -class, -newcmap, -screen,
  466.          * or -visual to be changed.
  467.          */
  468.  
  469.         for (i = 2; i < argc; i++) {
  470.         length = strlen(argv[i]);
  471.         if (length < 2) {
  472.             continue;
  473.         }
  474.         c = argv[i][1];
  475.         if (((c == 'c') && (strncmp(argv[i], "-class", length) == 0)
  476.             && (length >= 2))
  477.             || ((c == 'c') && (framePtr->mask == TOPLEVEL)
  478.             && (strncmp(argv[i], "-colormap", length) == 0))
  479.             || ((c == 's') && (framePtr->mask == TOPLEVEL)
  480.             && (strncmp(argv[i], "-screen", length) == 0))
  481.             || ((c == 'v') && (framePtr->mask == TOPLEVEL)
  482.             && (strncmp(argv[i], "-visual", length) == 0))) {
  483.             Tcl_AppendResult(interp, "can't modify ", argv[i],
  484.                 " option after widget is created", (char *) NULL);
  485.             result = TCL_ERROR;
  486.             goto done;
  487.         }
  488.         }
  489.         result = ConfigureFrame(interp, framePtr, argc-2, argv+2,
  490.             TK_CONFIG_ARGV_ONLY);
  491.     }
  492.     } else {
  493.     Tcl_AppendResult(interp, "bad option \"", argv[1],
  494.         "\": must be cget or configure", (char *) NULL);
  495.     result = TCL_ERROR;
  496.     }
  497.  
  498.     done:
  499.     Tcl_Release((ClientData) framePtr);
  500.     return result;
  501. }
  502.  
  503. /*
  504.  *----------------------------------------------------------------------
  505.  *
  506.  * DestroyFrame --
  507.  *
  508.  *    This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
  509.  *    to clean up the internal structure of a frame at a safe time
  510.  *    (when no-one is using it anymore).
  511.  *
  512.  * Results:
  513.  *    None.
  514.  *
  515.  * Side effects:
  516.  *    Everything associated with the frame is freed up.
  517.  *
  518.  *----------------------------------------------------------------------
  519.  */
  520.  
  521. static void
  522. DestroyFrame(memPtr)
  523.     char *memPtr;        /* Info about frame widget. */
  524. {
  525.     register Frame *framePtr = (Frame *) memPtr;
  526.  
  527.     Tk_FreeOptions(configSpecs, (char *) framePtr, framePtr->display,
  528.         framePtr->mask);
  529.     if (framePtr->colormap != None) {
  530.     Tk_FreeColormap(framePtr->display, framePtr->colormap);
  531.     }
  532.     ckfree((char *) framePtr);
  533. }
  534.  
  535. /*
  536.  *----------------------------------------------------------------------
  537.  *
  538.  * ConfigureFrame --
  539.  *
  540.  *    This procedure is called to process an argv/argc list, plus
  541.  *    the Tk option database, in order to configure (or
  542.  *    reconfigure) a frame widget.
  543.  *
  544.  * Results:
  545.  *    The return value is a standard Tcl result.  If TCL_ERROR is
  546.  *    returned, then interp->result contains an error message.
  547.  *
  548.  * Side effects:
  549.  *    Configuration information, such as text string, colors, font,
  550.  *    etc. get set for framePtr;  old resources get freed, if there
  551.  *    were any.
  552.  *
  553.  *----------------------------------------------------------------------
  554.  */
  555.  
  556. static int
  557. ConfigureFrame(interp, framePtr, argc, argv, flags)
  558.     Tcl_Interp *interp;        /* Used for error reporting. */
  559.     register Frame *framePtr;    /* Information about widget;  may or may
  560.                  * not already have values for some fields. */
  561.     int argc;            /* Number of valid entries in argv. */
  562.     char **argv;        /* Arguments. */
  563.     int flags;            /* Flags to pass to Tk_ConfigureWidget. */
  564. {
  565.     if (Tk_ConfigureWidget(interp, framePtr->tkwin, configSpecs,
  566.         argc, argv, (char *) framePtr, flags | framePtr->mask) != TCL_OK) {
  567.     return TCL_ERROR;
  568.     }
  569.  
  570.     if (framePtr->border != NULL) {
  571.     Tk_SetBackgroundFromBorder(framePtr->tkwin, framePtr->border);
  572.     }
  573.     if (framePtr->highlightWidth < 0) {
  574.     framePtr->highlightWidth = 0;
  575.     }
  576.     Tk_SetInternalBorder(framePtr->tkwin,
  577.         framePtr->borderWidth + framePtr->highlightWidth);
  578.     if ((framePtr->width > 0) || (framePtr->height > 0)) {
  579.     Tk_GeometryRequest(framePtr->tkwin, framePtr->width,
  580.         framePtr->height);
  581.     }
  582.  
  583.     if (Tk_IsMapped(framePtr->tkwin)) {
  584.     if (!(framePtr->flags & REDRAW_PENDING)) {
  585.         Tcl_DoWhenIdle(DisplayFrame, (ClientData) framePtr);
  586.     }
  587.     framePtr->flags |= REDRAW_PENDING;
  588.     }
  589.     return TCL_OK;
  590. }
  591.  
  592. /*
  593.  *----------------------------------------------------------------------
  594.  *
  595.  * DisplayFrame --
  596.  *
  597.  *    This procedure is invoked to display a frame widget.
  598.  *
  599.  * Results:
  600.  *    None.
  601.  *
  602.  * Side effects:
  603.  *    Commands are output to X to display the frame in its
  604.  *    current mode.
  605.  *
  606.  *----------------------------------------------------------------------
  607.  */
  608.  
  609. static void
  610. DisplayFrame(clientData)
  611.     ClientData clientData;    /* Information about widget. */
  612. {
  613.     register Frame *framePtr = (Frame *) clientData;
  614.     register Tk_Window tkwin = framePtr->tkwin;
  615.     GC gc;
  616.  
  617.     framePtr->flags &= ~REDRAW_PENDING;
  618.     if ((framePtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
  619.     return;
  620.     }
  621.  
  622.     if (framePtr->border != NULL) {
  623.     Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin),
  624.         framePtr->border, framePtr->highlightWidth,
  625.         framePtr->highlightWidth,
  626.         Tk_Width(tkwin) - 2*framePtr->highlightWidth,
  627.         Tk_Height(tkwin) - 2*framePtr->highlightWidth,
  628.         framePtr->borderWidth, framePtr->relief);
  629.     }
  630.     if (framePtr->highlightWidth != 0) {
  631.     if (framePtr->flags & GOT_FOCUS) {
  632.         gc = Tk_GCForColor(framePtr->highlightColorPtr,
  633.             Tk_WindowId(tkwin));
  634.     } else {
  635.         gc = Tk_GCForColor(framePtr->highlightBgColorPtr,
  636.             Tk_WindowId(tkwin));
  637.     }
  638.     Tk_DrawFocusHighlight(tkwin, gc, framePtr->highlightWidth,
  639.         Tk_WindowId(tkwin));
  640.     }
  641. }
  642.  
  643. /*
  644.  *--------------------------------------------------------------
  645.  *
  646.  * FrameEventProc --
  647.  *
  648.  *    This procedure is invoked by the Tk dispatcher on
  649.  *    structure changes to a frame.  For frames with 3D
  650.  *    borders, this procedure is also invoked for exposures.
  651.  *
  652.  * Results:
  653.  *    None.
  654.  *
  655.  * Side effects:
  656.  *    When the window gets deleted, internal structures get
  657.  *    cleaned up.  When it gets exposed, it is redisplayed.
  658.  *
  659.  *--------------------------------------------------------------
  660.  */
  661.  
  662. static void
  663. FrameEventProc(clientData, eventPtr)
  664.     ClientData clientData;    /* Information about window. */
  665.     register XEvent *eventPtr;    /* Information about event. */
  666. {
  667.     register Frame *framePtr = (Frame *) clientData;
  668.  
  669.     if (((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0))
  670.         || (eventPtr->type == ConfigureNotify)) {
  671.     goto redraw;
  672.     } else if (eventPtr->type == DestroyNotify) {
  673.     if (framePtr->tkwin != NULL) {
  674.         framePtr->tkwin = NULL;
  675.         Tcl_DeleteCommand(framePtr->interp,
  676.             Tcl_GetCommandName(framePtr->interp, framePtr->widgetCmd));
  677.     }
  678.     if (framePtr->flags & REDRAW_PENDING) {
  679.         Tcl_CancelIdleCall(DisplayFrame, (ClientData) framePtr);
  680.     }
  681.     Tcl_CancelIdleCall(MapFrame, (ClientData) framePtr);
  682.     Tcl_EventuallyFree((ClientData) framePtr, DestroyFrame);
  683.     } else if (eventPtr->type == FocusIn) {
  684.     if (eventPtr->xfocus.detail != NotifyInferior) {
  685.         framePtr->flags |= GOT_FOCUS;
  686.         if (framePtr->highlightWidth > 0) {
  687.         goto redraw;
  688.         }
  689.     }
  690.     } else if (eventPtr->type == FocusOut) {
  691.     if (eventPtr->xfocus.detail != NotifyInferior) {
  692.         framePtr->flags &= ~GOT_FOCUS;
  693.         if (framePtr->highlightWidth > 0) {
  694.         goto redraw;
  695.         }
  696.     }
  697.     }
  698.     return;
  699.  
  700.     redraw:
  701.     if ((framePtr->tkwin != NULL) && !(framePtr->flags & REDRAW_PENDING)) {
  702.     Tcl_DoWhenIdle(DisplayFrame, (ClientData) framePtr);
  703.     framePtr->flags |= REDRAW_PENDING;
  704.     }
  705. }
  706.  
  707. /*
  708.  *----------------------------------------------------------------------
  709.  *
  710.  * FrameCmdDeletedProc --
  711.  *
  712.  *    This procedure is invoked when a widget command is deleted.  If
  713.  *    the widget isn't already in the process of being destroyed,
  714.  *    this command destroys it.
  715.  *
  716.  * Results:
  717.  *    None.
  718.  *
  719.  * Side effects:
  720.  *    The widget is destroyed.
  721.  *
  722.  *----------------------------------------------------------------------
  723.  */
  724.  
  725. static void
  726. FrameCmdDeletedProc(clientData)
  727.     ClientData clientData;    /* Pointer to widget record for widget. */
  728. {
  729.     Frame *framePtr = (Frame *) clientData;
  730.     Tk_Window tkwin = framePtr->tkwin;
  731.  
  732.     /*
  733.      * This procedure could be invoked either because the window was
  734.      * destroyed and the command was then deleted (in which case tkwin
  735.      * is NULL) or because the command was deleted, and then this procedure
  736.      * destroys the widget.
  737.      */
  738.  
  739.     if (tkwin != NULL) {
  740.     framePtr->tkwin = NULL;
  741.     Tk_DestroyWindow(tkwin);
  742.     }
  743. }
  744.  
  745. /*
  746.  *----------------------------------------------------------------------
  747.  *
  748.  * MapFrame --
  749.  *
  750.  *    This procedure is invoked as a when-idle handler to map a
  751.  *    newly-created top-level frame.
  752.  *
  753.  * Results:
  754.  *    None.
  755.  *
  756.  * Side effects:
  757.  *    The frame given by the clientData argument is mapped.
  758.  *
  759.  *----------------------------------------------------------------------
  760.  */
  761.  
  762. static void
  763. MapFrame(clientData)
  764.     ClientData clientData;        /* Pointer to frame structure. */
  765. {
  766.     Frame *framePtr = (Frame *) clientData;
  767.  
  768.     /*
  769.      * Wait for all other background events to be processed before
  770.      * mapping window.  This ensures that the window's correct geometry
  771.      * will have been determined before it is first mapped, so that the
  772.      * window manager doesn't get a false idea of its desired geometry.
  773.      */
  774.  
  775.     Tcl_Preserve((ClientData) framePtr);
  776.     while (1) {
  777.     if (Tcl_DoOneEvent(TCL_IDLE_EVENTS) == 0) {
  778.         break;
  779.     }
  780.  
  781.     /*
  782.      * After each event, make sure that the window still exists
  783.      * and quit if the window has been destroyed.
  784.      */
  785.  
  786.     if (framePtr->tkwin == NULL) {
  787.         Tcl_Release((ClientData) framePtr);
  788.         return;
  789.     }
  790.     }
  791.     Tk_MapWindow(framePtr->tkwin);
  792.     Tcl_Release((ClientData) framePtr);
  793. }
  794.